/* ------------------------------------------------------------------------*
 *
 * ------------------------------------------------------------------------*/
#include "stdint.h"
#include "os_obj.h"
#include "systask.h"
#include "bsp_api.h"

#include "bsp_spi_nor.h"
#include "nor_cmd.h"

#include "str_ext.h"
#include "common.h"

#define GD25Q_CHIP_SIZE (16 * 1024 * 1024)

struct
{
	uint8_t check_req;		// 0空闲 1-spi	2-qpi，地址范围 start~end
	uint8_t read_req;		// 0空闲 1-spi	2-qpi，地址范围 start~end
	uint8_t sig_read_req;
	uint8_t sig_write_req;	
	uint8_t err;	    
    uint32_t dat;
	uint32_t dat_first;		// 数据递增起始值
	uint32_t addr;
	uint32_t addr_start;	// 扇区对齐
	uint32_t amount;		// 扇区对齐
	uint32_t tm_used;
	dword_tt *buff;
} nor;

/*-----------------------------------------------------------------------------------------------------*
* signal nor manage test
*-----------------------------------------------------------------------------------------------------*/
void nor_flash_fixed_test()
{
	bsp_qpi_port_init();
	nor_spi_init();
	
    flash_dbg_print("switch to gd25 nor test module \n");
    
    //初始化
    nor_init(1);

	nor.buff = malloc(4096);
    nor.read_req = 0;
	nor.addr_start = 0;
	nor.amount = 4096 * 4096;
	nor.dat_first = 0x12345678;
	
	set_u32(nor.buff, 0, 4096/4);
	
    for (;;)
    {
		if(sys_st.str_module != 0)
			break;
		
        osDelay(ms_ticks(10));

        //spi mode check
        if (1 == nor.check_req)
        {
			// 写入数据
            uint32_t dats = nor.dat = nor.dat_first;
            
            flash_dbg_print("fix spi mode check : start \n");
            
            for (nor.addr = nor.addr_start; nor.addr < nor.amount + nor.addr_start; nor.addr += SPI_NOR_PAGE_SIZE)
            {
                if (nor.addr % SPI_NOR_SECTOR_SIZE == 0)
                {
                    nor_sector_erase(nor.addr);
                }

                for (int index = 0; index < SPI_NOR_PAGE_SIZE / 4; index++)
                {
                    nor.buff[index].uVal = nor.dat++;
                }

				// 写入一页数据
                nor_write(nor.addr, SPI_NOR_PAGE_SIZE, nor.buff[0].v);
                
                if(0 == (nor.addr & 0x03FFFF))
                {
                    flash_dbg_print("fix spi mode check write data: %d %% \n", nor.addr * 100 / GD25Q_CHIP_SIZE );
                }
            }

			// 读回校验
            nor.dat = dats;
            flash_dbg_print("fix spi mode check : read and check \n");
            for (nor.addr = nor.addr_start; nor.addr < nor.amount + nor.addr_start; nor.addr += SPI_NOR_PAGE_SIZE)
            {
                if (nor.addr % SPI_NOR_SECTOR_SIZE == 0)
                {
					// 读取一扇区数据
                    nor_read(nor.addr, SPI_NOR_SECTOR_SIZE, nor.buff[0].v);

                    for (int index = 0; index < SPI_NOR_SECTOR_SIZE / 4; index++)
                    {
                        if (nor.buff[index].uVal != nor.dat)
                        {
                            nor.err++;
                        }
                        nor.dat++;
                    }
                    
                    if(nor.err)
                    {
                        flash_dbg_print("fix spi mode check err: %d @ %x \n", nor.err, nor.addr);
                        nor.err = 0;
                    }
                }
            }

            nor.check_req = 0;
            flash_dbg_print("fix spi mode check : end \n");
			
			set_u32(nor.buff, 0, 4096/4);
        }

        //qpi mode check
        if (2 == nor.check_req)
        {
			// 写入数据
            uint32_t dats = nor.dat = nor.dat_first;
            flash_dbg_print("fix qpi mode check : start \n");
            
            //spi
            for (nor.addr = nor.addr_start; nor.addr < nor.amount + nor.addr_start; nor.addr += SPI_NOR_PAGE_SIZE)
            {
                if (nor.addr % SPI_NOR_SECTOR_SIZE == 0)
                {
                    nor_sector_erase(nor.addr);
                }

                for (int index = 0; index < SPI_NOR_PAGE_SIZE / 4; index++)
                {
                    nor.buff[index].uVal = nor.dat++;
                }

				// 写入一页数据
                nor_q_write(nor.addr, SPI_NOR_PAGE_SIZE, nor.buff[0].v);
                
                if(0 == (nor.addr & 0x03FFFF))
                {
                    flash_dbg_print("fix qpi mode check write data: %d %% \n", nor.addr * 100 / GD25Q_CHIP_SIZE );
                }
            }

            nor.dat = dats;
            flash_dbg_print("fix qpi mode check : read and check \n");
            for (nor.addr = nor.addr_start; nor.addr < nor.amount + nor.addr_start; nor.addr += SPI_NOR_PAGE_SIZE)
            {
                if (nor.addr % SPI_NOR_SECTOR_SIZE == 0)
                {
					// 读取一扇区数据
                    nor_q_read(nor.addr, SPI_NOR_SECTOR_SIZE, nor.buff[0].v);

                    for (int index = 0; index < SPI_NOR_SECTOR_SIZE / 4; index++)
                    {
                        if (nor.buff[index].uVal != nor.dat)
                        {
                            nor.err++;
                        }
                        nor.dat++;
                    }
                    
                    if(nor.err)
                    {
                        flash_dbg_print("fix spi mode check err: %d @ %x \n", nor.err, nor.addr);
                        nor.err = 0;
                    }
                }
            }
            flash_dbg_print("fix qpi mode check : end \n");
            nor.check_req = 0;
			
			set_u32(nor.buff, 0, 4096/4);
        }
		
		// 读数据 
		if(nor.read_req)
		{
			uint32_t addr, tm_start, addr_end;
			
			addr_end = nor.amount + nor.addr_start;
			tm_start = sys_st.ticks;
			
			for(addr = nor.addr_start; addr < addr_end; addr+=2048)
			{
				if(nor.read_req == 1)
					nor_read(addr, 2048, nor.buff[0].v);
				else
					nor_q_read(addr, 2048, nor.buff[0].v);
			}
			
			nor.tm_used = sys_st.ticks - tm_start;
			
			nor.read_req = 0;
		}
		
		// 单读测试
		if(nor.sig_read_req)
		{
			memset(nor.buff, 0, 4096);
			
			if(nor.amount > 4096)
				nor.amount = 4096;
			
			if(nor.sig_read_req == 1)
				nor_read(nor.addr_start, nor.amount, &nor.buff[0].v[0]);
			else
				nor_q_read(nor.addr_start, nor.amount, &nor.buff[0].v[0]);
			
			nor.sig_read_req = 0;
		}
		
		// 单写测试
		if(nor.sig_write_req)
		{
			int cnt;
			
			nor_block_erase(nor.addr_start);
			
			if(nor.amount > 4096)
				nor.amount = 4096;
			
			for(cnt=0; cnt < 1024;cnt++)
			{
				nor.buff[cnt].word.LW.uval = cnt*2 + nor.dat_first;
				nor.buff[cnt].word.HW.uval = cnt*2 + nor.dat_first + 1;
			}
			
			if(nor.sig_write_req == 1)
				nor_write_multi(nor.addr_start, nor.amount, &nor.buff[0].v[2]);
			else
				nor_q_write_multi(nor.addr_start, nor.amount, &nor.buff[0].v[2]);
			
			nor.sig_write_req = 0;
		}
	}
	
	free(nor.buff);
}

/*-----------------------------------------------------------------------------------------------------*
* multi nor manage test
*-----------------------------------------------------------------------------------------------------*/
const multi_nor_type nor_bd =
{
    .cs = nor_spi_cs,
    .spi_mode = (void(*)(nor_spi_type))nor_spi_mode,
    .spi_rw = nor_spi_rw,
    .spi_cmd_send = nor_spi_cmd_send,
	.qpi_cmd_send = nor_qpi_cmd_send,
    .spi_write = nor_spi_write,
    .spi_read = nor_spi_read,
    .qpi_write = nor_qpi_write,
    .qpi_read = nor_qpi_read,
};

void nor_flash_dync_test()
{
	bsp_qpi_port_init();
	nor_spi_init();
	
    flash_dbg_print("switch to multi nor test module \n");
    
    //初始化
    multi_nor_init(&nor_bd, 1);

	nor.buff = malloc(4096);
    nor.read_req = 0;
	nor.addr_start = 0;
	nor.amount = 4096 * 8;
	nor.dat_first = 0x12345678;
	
	set_u32(nor.buff, 0, 4096/4);
	
    for (;;)
    {
		if(sys_st.str_module != 1)
			break;
		
        //spi mode check
        if (1 == nor.check_req)
        {
			// 写入数据
            uint32_t dats = nor.dat = nor.dat_first;

            for (nor.addr = nor.addr_start; nor.addr < nor.amount + nor.addr_start; nor.addr += SPI_NOR_PAGE_SIZE)
            {
                if (nor.addr % SPI_NOR_SECTOR_SIZE == 0)
                {
                    multi_nor_sector_erase(&nor_bd, nor.addr);
                }

                for (int index = 0; index < SPI_NOR_PAGE_SIZE / 4; index++)
                {
                    nor.buff[index].uVal = nor.dat++;
                }

				// 写入一页数据
                multi_nor_write(&nor_bd, nor.addr, SPI_NOR_PAGE_SIZE, nor.buff[0].v);
            }

			// 读回验证
            nor.dat = dats;
            for (nor.addr = nor.addr_start; nor.addr < nor.amount + nor.addr_start; nor.addr += SPI_NOR_PAGE_SIZE)
            {
                if (nor.addr % SPI_NOR_SECTOR_SIZE == 0)
                {
					// 读取一扇区数据
                    multi_nor_read(&nor_bd, nor.addr, SPI_NOR_SECTOR_SIZE, nor.buff[0].v);

                    for (int index = 0; index < SPI_NOR_SECTOR_SIZE / 4; index++)
                    {
                        if (nor.buff[index].uVal != nor.dat)
                        {
                            nor.err++;
                        }
                        nor.dat++;
                    }
                }
            }
            nor.check_req = 0;
			
			set_u32(nor.buff, 0, 4096/4);
        }

        //qpi mode check
        if (2 == nor.check_req)
        {
            uint32_t dats = nor.dat = nor.dat_first;

            // data write 0++
            for (nor.addr = nor.addr_start; nor.addr < nor.amount + nor.addr_start; nor.addr += SPI_NOR_PAGE_SIZE)
            {
                if (nor.addr % SPI_NOR_SECTOR_SIZE == 0)
                {
                    multi_nor_sector_erase(&nor_bd, nor.addr);
                }

                for (int index = 0; index < SPI_NOR_PAGE_SIZE / 4; index++)
                {
                    nor.buff[index].uVal = nor.dat++;
                }

				// 写入一页数据
                multi_nor_q_write(&nor_bd, nor.addr, SPI_NOR_PAGE_SIZE, nor.buff[0].v);
            }

			// 读回验证
            nor.dat = dats;
            for (nor.addr = nor.addr_start; nor.addr < nor.amount + nor.addr_start; nor.addr += SPI_NOR_PAGE_SIZE)
            {
                if (nor.addr % SPI_NOR_SECTOR_SIZE == 0)
                {
					// 读取一扇区数据
                    multi_nor_q_read(&nor_bd, nor.addr, SPI_NOR_SECTOR_SIZE, nor.buff[0].v);

                    for (int index = 0; index < SPI_NOR_SECTOR_SIZE / 4; index++)
                    {
                        if (nor.buff[index].uVal != nor.dat)
                        {
                            nor.err++;
                        }
                        nor.dat++;
                    }
                }
            }

            nor.check_req = 0;
			
			set_u32(nor.buff, 0, 4096/4);
        }

		// 读数据
		if(nor.read_req)
		{
			uint32_t addr, tm_start;
			
			tm_start = sys_st.ticks;
			
			for(addr = nor.addr_start; addr < nor.amount + nor.addr_start; addr+=4096)
			{
				if(nor.read_req == 1)
					multi_nor_read(&nor_bd,addr, 4096, nor.buff[0].v);
				else
					multi_nor_q_read(&nor_bd,addr, 4096, nor.buff[0].v);
			}
			
			nor.tm_used = sys_st.ticks - tm_start;
			
			nor.read_req = 0;
		}
		
        osDelay(ms_ticks(10));
    }
	
	free(nor.buff);
}
